package com.ecp.base.service;

import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.stereotype.Repository;

import com.ecp.commons.db.MongoDB;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;

@Repository("aliasCodeMongo")
public class AliasCodeMongoImpl implements AliasCodeMongo {
	protected DB		db					= null;

	private Random		rand				= new Random(System.currentTimeMillis());
	private String		lastDateStr			= "";
	private Set<String>	existAliascodeSet	= new HashSet<String>();

	@Resource(name = "mongodb")
	public void setDB(MongoDB mongodb) {
		db = mongodb.getMongoDB();
	}

	private long	serverId	= System.currentTimeMillis();
	private long	sequence	= rand.nextInt(1000000);

	@SuppressWarnings("deprecation")
	@Override
	public synchronized String generateAliasCode(String prefix) {
		Date date = new Date();
		++sequence;
		String dateString = prefix + DateFormatUtils.format(date, "yyMMdd");
		if (lastDateStr.length() == 0) {
			lastDateStr = dateString;
		} else if (!lastDateStr.equals(dateString) && date.getHours() >= 1) {
			this.clearLastDayCode(lastDateStr);
			lastDateStr = dateString;
		}
		String aliascode = "";
		do {
			String rNum = String.format("%06d", rand.nextInt(1000000));
			aliascode = dateString + rNum;
		} while (!this.insertToDB(aliascode));
		return aliascode;
	}

	private void clearLastDayCode(String lastDate) {
		DBCollection coll = db.getCollection("aliasCode");
		Pattern codeLike = Pattern.compile("^" + lastDate);
		coll.remove(new BasicDBObject("_id", codeLike));
	}

	private boolean insertToDB(String aliascode) {
		DBCollection coll = db.getCollection("aliasCode");
		BasicDBObject obj = new BasicDBObject("_id", aliascode);
		obj.put("svr", serverId);
		obj.put("sn", sequence);
		coll.insert(obj);
		return (coll.findOne(obj) != null); // insert OK
	}

	//@Override
	public synchronized String generateAliasCode2() {
		long start = System.currentTimeMillis();
		Date date = new Date();
		String dateString = DateFormatUtils.format(date, "yyMMdd");
		if (lastDateStr.length() == 0) {
			lastDateStr = dateString;
			this.loadFromDB();
		} else if (!lastDateStr.equals(dateString)) {
			lastDateStr = dateString;
			this.clearSetAndDB();
		}
		String aliascode = "";
		do {
			String rNum = String.format("%06d", rand.nextInt(1000000));
			aliascode = dateString + rNum;
		} while (existAliascodeSet.contains(aliascode));
		this.addToSetAndDB(aliascode);
		long end = System.currentTimeMillis();
		System.out.println("duration: " + (end - start));
		return aliascode;
	}

	private void loadFromDB() {
		DBCollection coll = db.getCollection("aliasCode");
		DBCursor cursor = coll.find();
		while (cursor.hasNext()) {
			BasicDBObject obj = (BasicDBObject) cursor.next();
			String aliasCode = obj.getString("_id");
			existAliascodeSet.add(aliasCode);
		}
	}

	private void clearSetAndDB() {
		existAliascodeSet.clear();
		DBCollection coll = db.getCollection("aliasCode");
		coll.drop();
	}

	private void addToSetAndDB(String aliascode) {
		existAliascodeSet.add(aliascode);
		DBCollection coll = db.getCollection("aliasCode");
		coll.insert(new BasicDBObject("_id", aliascode));
	}
}
